#include "stb_image.h"
#include "Alice/Resource/ResourceMngr.h"
#include "Alice/Resource/File.hpp"

namespace Alice
{

Shader& ResourceMngr::LoadShader(
    std::string name,
    const char* vertex_shader_file,
    const char* fragment_shader_file,
    const char* geometry_shader_file
)
{
    shaders[ name ] = LoadShaderFromFile(
        name, 
        vertex_shader_file, 
        fragment_shader_file,
        geometry_shader_file
    );

    ALICE_INFO("Successfully create shader: name: '{}' ID: {}", name, shaders[ name ].Id);

    return shaders[ name ];
}

Shader& ResourceMngr::GetShader(std::string name)
{
    if (shaders.find(name) == shaders.end())
        ALICE_WARN("Get a nonexistent shader: name: '{}'", name);

    return shaders[ name ];
}

Texture2D& ResourceMngr::LoadTexture(std::string name, const char* image_file)
{
    textures[ name ] = LoadTextureFromFile(image_file);
    ALICE_INFO("Successfully create texture: name: '{}' ID: {}", name, textures[ name ].Id);

    return textures[ name ];
}

Texture2D& ResourceMngr::GetTexture(std::string name)
{
    return textures[ name ];
}

void ResourceMngr::Clear()
{
    for (auto iter : shaders)
        glDeleteProgram(iter.second.Id);
    for (auto iter : textures)
        glDeleteTextures(1, &iter.second.Id);
    ALICE_INFO("Successfully clean all resources (shaders & textures)");
}

Shader ResourceMngr::LoadShaderFromFile(
    std::string name,
    const char* vertex_shader_file,
    const char* fragment_shader_file,
    const char* geometry_shader_file
)
{
    std::string vcode = File::Read(vertex_shader_file);
    std::string fcode = File::Read(fragment_shader_file);
    const char* vertex_shader_code = vcode.c_str();
    const char* fragment_shader_code = fcode.c_str();
    std::string geometry_shader_source;
    if (geometry_shader_file != nullptr)
    {
        geometry_shader_source = File::Read(geometry_shader_file);
    }
    ALICE_INFO("Successfully load vertex shader: {}", vertex_shader_file);
    ALICE_INFO("Successfully load fragment shader: {}", fragment_shader_file);

    Shader shader;
    shader.Compile(
        vertex_shader_code,
        fragment_shader_code,
        geometry_shader_file == nullptr ?
            nullptr : geometry_shader_source.c_str()
    );
    ALICE_INFO("Successfully compile vertex shader: {}", vertex_shader_file);
    ALICE_INFO("Successfully compile fragment shader: {}", fragment_shader_file);

    return shader;
}

Texture2D ResourceMngr::LoadTextureFromFile(const char* image_file)
{
    Texture2D texture;

    int width, height, nr_components;
    
    // 通过调整 model 数据，已实现本函数翻转图片的功能
    // stbi_set_flip_vertically_on_load(true);
    unsigned char* image = stbi_load(
        image_file, &width, &height, &nr_components, 0
    );

    if (image)
    {
        unsigned int format;
        if (nr_components == 1)
            format = GL_RED;
        else if (nr_components == 3)
            format = GL_RGB;
        else if (nr_components == 4)
            format = GL_RGBA;
            texture.internal_format = GL_RGBA;

        texture.image_format = format;
    }
    else
    {
        ALICE_ERROR("Load Texture2D failed: {}", image_file);
    }

    ALICE_INFO("Successfully loaded image: {} width: {} height: {}", image_file, width, height);
    
    texture.Generate(width, height, image);
    stbi_image_free(image);

    return texture;
}

} // namespace Alice
